package com.tcm.smarthealth.service.impl;

import com.mongodb.client.gridfs.model.GridFSFile;
import com.tcm.smarthealth.common.exception.BusinessException;
import com.tcm.smarthealth.document.ImageRecord;
import com.tcm.smarthealth.dto.ImageRecordResponse;
import com.tcm.smarthealth.enums.ImageAnalysisType;
import com.tcm.smarthealth.service.ImageService;
import com.tcm.smarthealth.service.ai.AiClient;
import com.tcm.smarthealth.service.ai.AiClientException;
import com.tcm.smarthealth.service.ai.AiInsight;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
public class ImageServiceImpl implements ImageService {

    private static final Logger log = LoggerFactory.getLogger(ImageServiceImpl.class);
    private static final int DEFAULT_PAGE_SIZE = 10;

    private final GridFsTemplate gridFsTemplate;
    private final MongoTemplate mongoTemplate;
    private final AiClient aiClient;

    public ImageServiceImpl(GridFsTemplate gridFsTemplate, MongoTemplate mongoTemplate, AiClient aiClient) {
        this.gridFsTemplate = gridFsTemplate;
        this.mongoTemplate = mongoTemplate;
        this.aiClient = aiClient;
    }

    @Override
    public ImageRecordResponse uploadAndAnalyze(MultipartFile file, ImageAnalysisType analysisType, Long userId) throws IOException {
        if (file == null || file.isEmpty()) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "请选择需要上传的图片");
        }

        String filename = StringUtils.hasText(file.getOriginalFilename()) ? file.getOriginalFilename() : "image-" + System.currentTimeMillis();
        Document metadata = new Document();
        metadata.put("analysisType", analysisType.name());
        metadata.put("userId", userId);

        byte[] bytes = file.getBytes();
        ObjectId fileId = gridFsTemplate.store(new ByteArrayInputStream(bytes), filename, file.getContentType(), metadata);

        ImageRecord record = new ImageRecord();
        record.setId(new ObjectId().toHexString());
        record.setUserId(userId);
        record.setFilename(filename);
        record.setContentType(file.getContentType());
        record.setFileSize(file.getSize());
        record.setAnalysisType(analysisType.name());
        record.setGridFsFileId(fileId.toHexString());
        record.setCreatedAt(LocalDateTime.now());

        AiInsight insight = resolveInsight(bytes, filename, analysisType);
        record.setDiagnosis(insight.getDiagnosis());
        record.setSuggestions(insight.getSuggestions() != null ? new ArrayList<>(insight.getSuggestions()) : new ArrayList<>());
        record.setConfidence(insight.getConfidence());

        mongoTemplate.save(record);

        return toResponse(record);
    }

    @Override
    public List<ImageRecordResponse> listRecords(Long userId, ImageAnalysisType analysisType, int page, int size) {
        int pageNo = Math.max(page, 1) - 1;
        int pageSize = size > 0 ? size : DEFAULT_PAGE_SIZE;

        Query query = new Query(Criteria.where("user_id").is(userId));
        if (analysisType != null) {
            query.addCriteria(Criteria.where("analysis_type").is(analysisType.name()));
        }
        query.with(Sort.by(Sort.Direction.DESC, "created_at"));
        query.skip((long) pageNo * pageSize).limit(pageSize);

        List<ImageRecord> records = mongoTemplate.find(query, ImageRecord.class);
        List<ImageRecordResponse> responses = new ArrayList<>();
        for (ImageRecord record : records) {
            responses.add(toResponse(record));
        }
        return responses;
    }

    @Override
    public ImageRecordResponse getRecord(String recordId, Long userId) {
        ImageRecord record = findRecord(recordId, userId);
        return toResponse(record);
    }

    @Override
    public Resource loadPreview(String recordId, Long userId) {
        ImageRecord record = findRecord(recordId, userId);
        ObjectId fileObjectId;
        try {
            fileObjectId = new ObjectId(record.getGridFsFileId());
        } catch (IllegalArgumentException ex) {
            log.error("Invalid GridFS file id: {}", record.getGridFsFileId(), ex);
            throw new BusinessException(HttpStatus.INTERNAL_SERVER_ERROR, "影像文件标识异常，请重新上传");
        }

        GridFSFile gridFsFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileObjectId)));
        if (gridFsFile == null) {
            GridFsResource legacyResource = gridFsTemplate.getResource(record.getGridFsFileId());
            if (legacyResource != null && legacyResource.exists()) {
                return legacyResource;
            }
            throw new BusinessException(HttpStatus.NOT_FOUND, "未找到原始图片文件");
        }

        GridFsResource resource = gridFsTemplate.getResource(gridFsFile);
        if (resource == null || !resource.exists()) {
            throw new BusinessException(HttpStatus.NOT_FOUND, "未找到原始图片文件");
        }
        return resource;
    }

    private ImageRecord findRecord(String recordId, Long userId) {
        Query query = new Query(Criteria.where("_id").is(recordId).and("user_id").is(userId));
        ImageRecord record = mongoTemplate.findOne(query, ImageRecord.class);
        if (record == null) {
            throw new BusinessException(HttpStatus.NOT_FOUND, "记录不存在或无访问权限");
        }
        return record;
    }

    private ImageRecordResponse toResponse(ImageRecord record) {
        ImageRecordResponse response = new ImageRecordResponse();
        response.setId(record.getId());
        response.setFilename(record.getFilename());
        response.setContentType(record.getContentType());
        response.setFileSize(record.getFileSize());
        response.setAnalysisType(record.getAnalysisType());
        response.setDiagnosis(record.getDiagnosis());
        response.setSuggestions(record.getSuggestions());
        response.setConfidence(record.getConfidence());
        response.setCreatedAt(record.getCreatedAt());
        response.setPreviewUrl("/v1/images/" + record.getId() + "/preview");
        return response;
    }

    private AiInsight resolveInsight(byte[] bytes, String filename, ImageAnalysisType type) {
        try {
            AiInsight insight = aiClient.analyzeImage(bytes, filename, type);
            if (!StringUtils.hasText(insight.getDiagnosis()) && !CollectionUtils.isEmpty(insight.getSuggestions())) {
                insight.setDiagnosis("AI 返回结果为空，请结合建议进行参考。");
            }
            if (insight.getConfidence() == null || insight.getConfidence().compareTo(BigDecimal.ZERO) <= 0) {
                insight.setConfidence(BigDecimal.valueOf(0.9));
            }
            return insight;
        } catch (AiClientException ex) {
            log.error("AI 图像分析失败: {}", ex.getMessage(), ex);
            throw new BusinessException(HttpStatus.BAD_GATEWAY, "AI 图像分析服务暂不可用，请稍后重试");
        }
    }
}

